import socket from '@ohos.net.socket'
import wifi from "@ohos.wifi"

import AgriculturalSystemData from "./AgriculturalSystemData"

class TcpProcess {
  private tcp: socket.TCPSocket
  // 服务端IP地址
  private remote_ip_address: string = "192.168.130.1"
  // 服务端端口号
  private remote_port: number = 8000

  /***************************************************************
   * 函数名称: constructor
   * 说    明: 类初始化时，触发该函数
   *          初始化TCP，并配置接收回调函数
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  constructor() {
    // tcp链接对象
    this.tcp = socket.constructTCPSocketInstance()
    // 创建目标地址和端口
    let remote: socket.NetAddress = {
      address: this.remote_ip_address,
      port: this.remote_port,
      family: 1, // IPv4
    }
    // 获取本地地址
    let local_ip_address: string = this.ipNumber2String(wifi.getIpInfo().ipAddress)
    console.log(`TcpProcess: constructor() => local_ip_address = ${local_ip_address}`)

    // 绑定端口号
    this.tcp.bind({ address: local_ip_address, port: 8000, family: 1}).then(() => {
      console.log("TcpProcess: constructor() => tcp bind sucessful")
    }).catch(error => {
      console.error(`TcpProcess: constructor() => tcp bind failed and error = ${JSON.stringify(error)}`)
    })

    // 连接服务器
    this.tcp.connect({
      address: remote,
      timeout: 5000,
    }).then(() => {
      console.log("TcpProcess: constructor() => tcp connect successful")
    }).catch((error) => {
      console.error(`TcpProcess: constructor() => tcp connect failed and error = ${JSON.stringify(error)}`)
    })

    // 注册相关回调函数
    this.tcp.on('connect', this.tcp_connect)
    this.tcp.on('close', this.tcp_disconnect)
    this.tcp.on('message', this.tcp_recv)
  }

  /***************************************************************
   * 函数名称: init
   * 说    明: 类初始化
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  init() {

  }


  /***************************************************************
   * 函数名称: reconnect
   * 说    明: 重新连接
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  reconnect() {
    // 目标地址和端口
    let remote: socket.NetAddress = {
      address: this.remote_ip_address,
      port: this.remote_port,
      family: 1, // IPv4
    }
    // 连接服务器
    this.tcp.connect({
      address: remote,
      timeout: 5000,
    }).then(() => {
      console.log("TcpProcess: constructor() => tcp connect successful")
    }).catch((error) => {
      console.error(`TcpProcess: constructor() => tcp connect failed and error = ${JSON.stringify(error)}`)
    })
  }


  /***************************************************************
   * 函数名称: ipNumber2String
   * 说    明: 将数字的IP地址转化为字符串
   * 参    数:
   *      @ip   网络IP地址，number类型
   * 返 回 值: 无
   ***************************************************************/
  ipNumber2String(ip: number) {
    if (ip < 0 || ip > 0xFFFFFFFF) {
      throw ("The number is not normal!");
    }
    return (ip >>> 24) + "." + (ip >> 16 & 0xFF) + "." + (ip >> 8 & 0xFF) + "." + (ip & 0xFF);
  }


  /***************************************************************
   * 函数名称: arrayBuffer2String
   * 说    明: 解析ArrayBuffer
   * 参    数:
   *        @message      ArrayBuffer类型的字符串
   * 返 回 值: string类型的字符串
   ***************************************************************/
  arrayBuffer2String(message: ArrayBuffer): string {
    if (message instanceof ArrayBuffer) {
      let dataView = new DataView(message)
      let str = ""
      for (let i = 0; i < dataView.byteLength; ++i) {
        let c = String.fromCharCode(dataView.getUint8(i))
        str += c
        // if (c !== "\n") {
        //   str += c
        // }
      }
      return str;
    }
  }


  /***************************************************************
   * 函数名称: string2ArrayBuffer_Uint16Array
   * 说    明: 将String转化为ArrayBuffer（16位）
   * 参    数:
   *      @str    String类型的字符串
   * 返 回 值: 返回ArrayBuffer类型的字符串
   ***************************************************************/
  string2ArrayBuffer_Uint16Array(str: String): ArrayBuffer {
    var bytes = new Array();
    var len, c;
    len = str.length;
    for (var i = 0; i < len; i++) {
      c = str.charCodeAt(i);
      if (c >= 0x010000 && c <= 0x10FFFF) {
        bytes.push(((c >> 18) & 0x07) | 0xF0);
        bytes.push(((c >> 12) & 0x3F) | 0x80);
        bytes.push(((c >> 6) & 0x3F) | 0x80);
        bytes.push((c & 0x3F) | 0x80);
      } else if (c >= 0x000800 && c <= 0x00FFFF) {
        bytes.push(((c >> 12) & 0x0F) | 0xE0);
        bytes.push(((c >> 6) & 0x3F) | 0x80);
        bytes.push((c & 0x3F) | 0x80);
      } else if (c >= 0x000080 && c <= 0x0007FF) {
        bytes.push(((c >> 6) & 0x1F) | 0xC0);
        bytes.push((c & 0x3F) | 0x80);
      } else {
        bytes.push(c & 0xFF);
      }
    }
    var array = new Int8Array(bytes.length);
    for (var i = 0; i <= bytes.length; i++) {
      array[i] = bytes[i];
    }
    return array.buffer;
  }


  /***************************************************************
   * 函数名称: string2ArrayBuffer_Uint8Array
   * 说    明: 将字符串转化为字符（8位）
   * 参    数:
   *      @str    string类型的字符串
   * 返 回 值: ArrayBuffer类型的字符串
   ***************************************************************/
  string2ArrayBuffer_Uint8Array(str: string) : ArrayBuffer {
    let i: number = 0
    let bufArray: ArrayBuffer = new ArrayBuffer(str.length)
    let bufView: ArrayBufferView = new Uint8Array(bufArray)
    // console.log(`TcpProcess: str.length = ${str.length}`)
    for (i = 0; i < str.length; i++) {
      bufView[i] = str.charCodeAt(i)
      // console.log(`TcpProcess: ${i} = ${str.charCodeAt(i)}, ${bufView[i]}`)
    }
    return bufArray
  }

  /***************************************************************
   * 函数名称: tcp_connect
   * 说    明: tcp链接通后，调用该函数
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  tcp_connect() {
    console.log("TcpProcess: tcp_connect() => connect successful")
  }

  /***************************************************************
   * 函数名称: tcp_disconnect
   * 说    明: tcp链接断开后，调用该函数
   * 参    数: 无
   * 返 回 值: 无
   ***************************************************************/
  tcp_disconnect() {
    console.log("TcpProcess: tcp_disconnect() => disconnect successful")
  }

  /***************************************************************
   * 函数名称: tcp_send
   * 说    明: tcp发送字符串给服务端
   * 参    数:
   *      @str    准备发送的字符串
   * 返 回 值: 无
   ***************************************************************/
  tcp_send(str: string) : void {
    // string转化为ArrayBuffer
    let buffer: ArrayBuffer = this.string2ArrayBuffer_Uint8Array(str)
    this.tcp.send({
      data: buffer,
    }, error => {
      if (error) {
        console.error(`TcpProcess: tcp_disconnect() => send failed and error = ${JSON.stringify(error)}`)
        this.reconnect()
      }
    })
  }

  /***************************************************************
   * 函数名称: tcp_recv
   * 说    明: tcp接收回调函数
   * 参    数:
   *      @value    接收到的报文，包括数据内容、IP地址等信息
   * 返 回 值: 无
   ***************************************************************/
  tcp_recv = (value) => {
    let message = value.message
    let remote = value.remoteInfo
    // 将ArrayBuffer转化为string
    let str: string = this.arrayBuffer2String(message)
    // 转发给AgriculturalSystemData
    AgriculturalSystemData.pushString(str)
    // 打印接收到的信息
    console.log(`TcpProcess: tcp_recv() => str.length = ${str.length}`)
    console.log(`TcpProcess: tcp_recv() => str = ${str}`)
    console.log(`TcpProcess: tcp_recv() => message.length = ${message.byteLength}`)
    // let i: number = 0
    // for (i = 0; i < str.length; i++) {
    //   console.log(`TcpProcess: tcp_recv() => str[${i}] = ${str.charCodeAt(i)}`)
    // }
  }
}

export default new TcpProcess()